package com.henry.th;

import java.util.Random;

class ProducerThread extends Thread {
    final int MAX_PRODUCE_INTERVAL_MS = 500;

    private final Buffer<Integer> bufferToUse;
    private final boolean reverse;
    private int maxProduce;

    public ProducerThread(Buffer<Integer> bufferIn, boolean reverseIn, int maxProduce) {
        this.bufferToUse = bufferIn;
        this.reverse = reverseIn;
        this.maxProduce = maxProduce;
    }

    @Override
    public void run() {
        int i = 1;
        int objToWrite;
        while (i <= maxProduce) {
            objToWrite = reverse ? maxProduce - i + 1 : i;
            bufferToUse.write(objToWrite);
            i = i + 1;
            System.out.println("Put " + objToWrite + "\t@ " + bufferToUse);

            try {
                // wait for a random interval
                Random r = new Random();
                Thread.sleep(r.nextInt(MAX_PRODUCE_INTERVAL_MS));
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
    }
}

class ConsumerThread extends Thread {
    final int MAX_CONSUME_INTERVAL_MS = 5;

    private final Buffer<Integer> bufferToUse;
    private int readTimes;

    public ConsumerThread(Buffer<Integer> bufferIn, int count) {
        this.bufferToUse = bufferIn;
        this.readTimes = count;
    }

    @Override
    public void run() {
        while (readTimes > 0) {
            Integer val = bufferToUse.read();
            readTimes -= 1;
            System.out.println("Got " + val + "\t@ " + bufferToUse);

            try {
                // wait for a random interval
                Random r = new Random();
                Thread.sleep(r.nextInt(MAX_CONSUME_INTERVAL_MS));
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
    }
}

public class CircularBufferDemo {

    public static void main(String[] args) {
        final int MAX_PRODUCE_NUMBER = 100;

        Integer[] a = new Integer[5];
        CircularBuffer<Integer> q = new CircularBuffer<>(a);

        ProducerThread p1 = new ProducerThread(q, true, MAX_PRODUCE_NUMBER);
        ProducerThread p2 = new ProducerThread(q, false, MAX_PRODUCE_NUMBER);

        ConsumerThread consumer = new ConsumerThread(q, 2 * MAX_PRODUCE_NUMBER);

        p1.start();
        p2.start();
        consumer.start();
    }
}
